#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2025/6/3 19:58
# @Author  : wuyupeng
# @FileName: repo_manager.py
# @Software: PyCharm
import abc
import sys
import importlib
import logging
from pathlib import Path


logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")


class RepoManager(abc.ABC):
    def __init__(self, pkg_path: str, is_debug: bool=False):
        self._pkg_path = Path(pkg_path)
        self._pkg_name = None
        self._pkg_version = None
        self.is_debug = is_debug

    def prepare_package(self, *args, **kwargs) -> Path:
        self.parse_name_and_version()
        
        if not self._pkg_name or not self._pkg_version:
            raise ValueError(f"解析包信息失败 - 包名: {self._pkg_name} - 版本: {self._pkg_version}")

        target_path = self.construct_package_locally(*args, **kwargs)
        logging.info(f"本地包生成完成：{target_path}")
        return target_path

    def upload_package(self, pkg_root, *args, **kwargs):
        if self.check_version_exist():
            return
        self.push_to_repo(pkg_root, *args, **kwargs)

    def debug(self, msg):
        if not self.is_debug:
            return
        logging.info(f"[DEBUG] {msg}")

    def update_dists(self, target_pkg: str, target_version: str, *args, **kwargs) -> Path:
        """ 包删除时通过传参初始化包名和版本号 """
        self._pkg_name = target_pkg
        self._pkg_version = target_version

        target_path = self.construct_package_locally(*args, **kwargs)
        return target_path

    @abc.abstractmethod
    def parse_name_and_version(self):
        """ 解析包名和版本号 """

    @abc.abstractmethod
    def check_version_exist(self):
        """ 检查版本是否存在，存在就不再上传 """

    @abc.abstractmethod
    def push_to_repo(self, pkg_root: Path, *args, **kwargs):
        """ 推包上库 """
    
    @abc.abstractmethod
    def construct_package_locally(self, *args, **kwargs) -> Path:
        """ 构建本地包 """

    @abc.abstractmethod
    def delete_package(self, *args, **kwargs) -> bool:
        """ 包删除接口 """


class RepoManagerFactory:
    _instance = None
    _registry = {}

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
            cls._init_registry()
        return cls._instance

    @classmethod
    def _init_registry(cls):
        cls._registry = {}
        cls._discover_impls()

    @classmethod
    def register(cls, type_name):
        def wrapper(subclass):
            cls._registry[type_name] = subclass
            return subclass
        return wrapper

    @classmethod
    def create(cls, type_name, *args, **kwargs):
        if type_name not in cls._registry:
            cls._discover_impls()

        if type_name not in cls._registry:
            raise ValueError(f"未定义的仓库：{type_name}")

        return cls._registry[type_name](*args, **kwargs)
    
    @classmethod
    def _discover_impls(cls):
        impls = Path(__file__).parent / 'impls'
        for inst in impls.glob("*.py"):
            if inst.name == "__init__.py":
                continue

            module_name = inst.stem
            if module_name in sys.modules:
                continue

            spec = importlib.util.spec_from_file_location(f"impl_{module_name}", inst)
            if not spec or not spec.loader:
                continue

            try:
                module = importlib.util.module_from_spec(spec)
                sys.modules[module_name] = module
                spec.loader.exec_module(module)
            except Exception as e:
                logging.exception(f"加载 {inst} 失败: {str(e)}")
